<?php


namespace app\api\model;
use app\common\library\dingding\AliDingDing;
use app\common\library\Hiflux;
use app\common\library\himongo;
use app\common\library\IDMan;
use app\common\library\PlatformModel;
use common;
use ApiOper;
use think\db\Query;
use think\Exception;
use vtimer;
use hiredis;
use think\Db;
use think\facade\Log;

class BikeModel
{
    static $attrib_map_user = [
        'health_state' => 'int',
        'park_state' => 'int',
        'inv_state' => 'int',
        'bus_state' => 'int',
        'alert_state' => 'int',
        'battery_level' => 'int',
        'battery_range' => 'int',
        'is_under_volt' => 'int',
        'coordinate' => 'array',
        'address' => 'string',
        'is_low_battery' => 'int',
        'is_defend_on' => 'int',
        'id' => 'string',
        'sn' => 'string',
        'bluetooth_name' => 'string',
        'ecu_model' => 'string',
        'ecu_sn' => 'string',
        'bluetooth_token'=> 'string',
    ];

    static function user_filter($info)
    {
        return common::type_conver($info, self::$attrib_map_user);
    }

    var $summary_selectlist = [
        'health_state' => 'int',
        'park_state' => 'int',
        'inv_state' => 'int',
        'bus_state' => 'int',
        'alert_state' => 'int',
        'is_battery_locked' => 'int',
        'is_acc_on' => 'int',
        'is_wheel_locked' => 'int',
        'battery_volt' => 'int',
        'battery_level' => 'int',
        'battery_range' => 'int',
        'is_under_volt' => 'int',
        'coordinate' => 'array',
        'address' => 'string',
        'is_deleted' => 'int',
        'is_on_battery' => 'int',
        'is_low_battery' => 'int',
        'is_defend_on' => 'int',
        'repark_index' => 'int',
    ];

    var $selectlist = [
        'id' => 'string',
        'sn' => 'string',
        'city_id' => 'string',
        'model' => 'string',
        'product_batch_number' => 'string',
        'ecu_brand' => 'string',
        'ecu_model' => 'string',
        'imei' => 'string',
        'ecu_sn' => 'string',
        'health_state' => 'int',
        'health_desc' => 'int',
        'park_state' => 'int',
        'park_id' => 'string',
        'park_name' => 'string',
        'npa_id' => 'string',
        'npa_name' => 'string',
        'inv_state' => 'int',
        'warehouse_id' => 'string',
        'warehouse_name' => 'string',
        'bus_state' => 'int',
        'sim_state' => 'int',
        'alert_state' => 'int',
        'speed' => 'int',
        'is_in_motion' => 'int',
        'is_online' => 'int',
        'svca_id' => 'string',
        'svca_name' => 'string',
        'is_battery_locked' => 'int',
        'is_acc_on' => 'int',
        'is_wheel_locked' => 'int',
        'is_wheel_span' => 'int',
        'battery_volt' => 'int',
        'battery_level' => 'int',
        'battery_range' => 'int',
        'battery_update_time' => 'string',
        'is_under_volt' => 'int',
        'last_order_start_time' => 'string',
        'last_order_end_time' => 'string',
        'last_order_id' => 'string',
        'last_order_type' => 'int',
        'last_order_oper_id' => 'string',
        'last_order_oper_name' => 'string',
        'last_order_oper_phone' => 'string',
        'brand' => 'string',
        'coordinate' => 'array',
        'address' => 'string',
        'gps_update_time' => 'string',
        'park_update_time' => 'string',
        'bus_update_time' => 'string',
        'motion_update_time' => 'string',
        'health_update_time' => 'string',
        'creator_id' => 'string',
        'creator_name' => 'string',
        'create_time' => 'string',
        'updater_id' => 'string',
        'updater_name' => 'string',
        'update_time' => 'string',
        'is_deleted' => 'int',
        'launch_time' => 'string',
        'battery_change_count' => 'int',
        'battery_capacity' => 'int',
        'inv_update_time' => 'string',
        'is_on_battery' => 'int',
        'is_low_battery' => 'int',
        'course' => 'int',
        'hdop' => 'float',
        'satellite' => 'int',
        'is_defend_on' => 'int',
        'is_sleeping' => 'int',
        'online_update_time' => 'string',
        'gsm_signal_strength' => 'string',
        'sw' => 'int',
        'address_update_time' => 'string',
        'last_maintain_time' => 'string',
        'last_maintain_user_name' => 'string',
        'last_maintain_user_id' => 'string',
        'maintain_count' => 'int',
        'defend_update_time' => 'string',
        'battery_lock_update_time' => 'string',
        'repark_index' => 'int',
        'battery_model' => 'string',
        'last_repark_order_type' => 'string',
        'last_repark_order_id' => 'string',
        'last_repark_order_oper_id' => 'string',
        'last_repark_order_oper_name' => 'string',
        'last_repark_order_oper_phone' => 'string',
        'last_repark_order_start_time' => 'string',
        'last_repark_order_end_time' => 'string',
        'last_battery_change_order_id' => 'string',
        'last_battery_change_order_oper_id' => 'string',
        'last_battery_change_order_oper_name' => 'string',
        'last_battery_change_order_oper_phone' => 'string',
        'last_battery_change_order_start_time' => 'string',
        'last_battery_change_order_end_time' => 'string',
        'locate_type' => 'string',
        'last_scaned_time' => 'string',
        'last_scaned_user_id' => 'string',
        'last_scaned_user_name' => 'string',
        'last_scaned_user_coordinate' => 'array',
        'park_coordinate' => 'array',
        'bluetooth_token' => 'string',
        'bluetooth_name' => 'string',
        'last_warn_time' => 'string',
        'is_dispatched' => 'int',
        'is_warned' => 'int',
        'is_flush_order_count' => 'int',
        'distance' => 'int',
    ];
    var $_info = [];

    /**
     * @return BikeModel|null
     */

    static function instance($reset = false)
    {
        static $ins = null;
        if (empty($ins) || $reset) {
            $ins = new BikeModel();
        }
        return $ins;
    }

    var $mongo_field = [
        'id' => 'string',
        'sn' => 'string',
        'city_id' => 'string',
        'imei' => 'string',
        'health_state' => 'int',
        'health_update_time' => 'string',
        'park_state' => 'int',
        'bus_state' => 'int',
        'inv_state' => 'int',
        'sim_state' => 'int',
        'alert_state' => 'int',
        'is_in_motion' => 'int',
        'is_online' => 'int',
        'is_battery_locked' => 'int',
        'is_acc_on' => 'int',
        'is_wheel_locked' => 'int',
        'battery_volt' => 'int',
        'battery_level' => 'int',
        'battery_update_time' => 'string',
        'is_under_volt' => 'int',
        'coordinate' => 'array',
        'address' => 'string',
        'is_deleted' => 'int',
        'is_on_battery' => 'int',
        'is_low_battery' => 'int',
        'is_defend_on' => 'int',
        'is_sleeping' => 'int',
        'sw' => 'int',
        'maintain_count' => 'int',
        'model' => 'string',
        'repark_index' => 'int',
        'online_update_time' => 'string',
        'bus_update_time' => 'string',
        'last_maintain_time' => 'string',
        'park_coordinate' => 'array',
        'distance' => 'int',
    ];

    function save_to_mongo($bike_info)
    {

        $where = [
            'eftype' => EB_TYPE_BIKE,
            'city_id' => $bike_info['city_id'],
            'id' => $bike_info['id'],
        ];

        himongo::db()->delete($where);
        $info = common::type_conver($bike_info, $this->mongo_field);
        if ($info['is_deleted'] == 0) {
            $info['eftype'] = EB_TYPE_BIKE;
            if (isset($info['coordinate'])) {
                $info['point'] = [
                    'type' => 'Point',
                    'coordinates' => $info['coordinate'],
                ];
            }
            himongo::db()->insert($info);
        }

    }

    function sync_to_mongo($data, $where)
    {
        $info = common::type_conver($data, $this->mongo_field);
        if (empty($info))
            return;

        if (isset($info['coordinate'])) {
            $info['point'] = [
                'type' => 'Point',
                'coordinates' => $info['coordinate'],
            ];
        }

        if (isset($info['is_deleted']) && $info['is_deleted'] == 1) {
            himongo::db()->delete($where);
            return;
        }

        $where['eftype'] = EB_TYPE_BIKE;

        $ret = himongo::db()->update($where, $info);

        if ($ret === 0) {
            $bike_info = (new BikeModel())->get_info_by_id($where['id']);
            if (!empty($bike_info)) {
                $this->save_to_mongo($bike_info);
            } else {
                Log::warning("sync_to_mongo ERROR");
            }
        }
    }

    function merge_info($info)
    {
        if (!empty($this->_info) || (empty($this->_info) && isset($info['id']))) {
            $this->_info = array_merge($this->_info, $info);
        }
    }

    function get_coordinate_by_id($bike_id)
    {
        $selectlist = [
            'coordinate' => 'array',
        ];
        $sfs = common::array_keys($selectlist);

        $rows = Db::table('think_user')->where('id',$bike_id)->field($sfs)->find();

        if (empty($rows)) {
            return null;
        }
        $info = common::sql_row($selectlist, $rows);
        return $info['coordinate'];
    }

    function get_info_by_id($bike_id)
    {
        if (!empty($this->_info) && $this->_info['id'] == $bike_id) {
            return $this->_info;
        }

        $sfs =  common::array_keys($this->selectlist);

        $beans = [
            'id'=>$bike_id,
            'is_deleted' => 0
        ];

        $rows = Db::table('think_user')->where($beans)->field($sfs)->find();
        if (empty($rows)) {
            return null;
        }
        $info = common::sql_row($this->selectlist, $rows);
        $this->merge_info($info);
        return $this->_info;
    }

    function get_info_by_sn($sn)
    {
        if (!empty($this->_info) && $this->_info['sn'] == $sn) {
            return $this->_info;
        }

        $sfs =  common::array_keys($this->selectlist);

        $beans = [
            'sn'=>$sn,
            'is_deleted' => 0
        ];

        $rows = Db::table('think_user')->where($beans)->field($sfs)->find();
        if (empty($rows)) {
            return null;
        }
        $info = common::sql_row($this->selectlist, $rows);
        $this->merge_info($info);
        return $this->_info;
    }

    function get_info_by_imei($imei)
    {
        if (!empty($this->_info) && $this->_info['imei'] == $imei) {
            return $this->_info;
        }

        $sfs =  common::array_keys($this->selectlist);

        $beans = [
            'imei'=>$imei,
            'is_deleted' => 0
        ];

        $rows = Db::table('think_user')->where($beans)->field($sfs)->find();
        if (empty($rows)) {
            return null;
        }
        $info = common::sql_row($this->selectlist, $rows);
        $this->merge_info($info);
        return $this->_info;
    }

    function get_info_by_ecu_sn($ecu_sn)
    {
        if (!empty($this->_info) && $this->_info['ecu_sn'] == $ecu_sn) {
            return $this->_info;
        }

        $sfs =  common::array_keys($this->selectlist);

        $beans = [
            'ecu_sn'=>$ecu_sn,
            'is_deleted' => 0
        ];

        $rows = Db::table('think_user')->where($beans)->field($sfs)->find();
        if (empty($rows)) {
            return null;
        }
        $info = common::sql_row($this->selectlist, $rows);
        $this->merge_info($info);
        return $this->_info;
    }

    function get_list($city_id, $condition, $pos, $limit)
    {

        $sfs = common::array_keys($this->selectlist);

        $beans = [
            'is_deleted' => 0
        ];

        if ($city_id) {
            $beans['city_id'] = $city_id;
        }

        if (isset($condition['is_in_service_area'])) {
            if ($condition['is_in_service_area'] > 0) {
                $beans['park_state'] = ['<>',BIKE_PARK_STAT_OSA];
            } else {
                $beans['park_state'] = ['=',BIKE_PARK_STAT_OSA];
            }
        }

        if (isset($condition['is_in_no_parking_area'])) {
            if ($condition['is_in_no_parking_area'] > 0) {
                $beans['park_state'] = ['=',BIKE_PARK_STAT_NPA];
            } else {
                $beans['park_state'] = ['<>',BIKE_PARK_STAT_NPA];
            }
        }

        if (isset($condition['is_defend_on'])) {
            $beans['is_defend_on'] = $condition['is_defend_on'];
        }

        if (isset($condition['health_state'])) {
            $beans['health_state'] = $condition['health_state'];
        }

        if (isset($condition['battery_level_upper'])) {
            $beans['battery_level_upper'] = ['<=',$condition['battery_level_upper']];
        }
        if (isset($condition['is_wheel_locked'])) {
            $beans['is_wheel_locked'] = $condition['is_wheel_locked'];
        }
        if (isset($condition['model'])) {;
            $beans['model'] = $condition['model'];
        }
        if (isset($condition['bus_state'])) {
            $beans['bus_state'] = $condition['bus_state'];
        }
        if (isset($condition['inv_state'])) {
            $beans['inv_state'] = $condition['inv_state'];
        }
        if (isset($condition['sk']) && !empty($condition['sk'])) {
            $sk = $condition['sk'];
            if (IDMan::is_bike_id($sk)) {
                $beans['id'] = $sk;
            } else if (IDMan::is_bike_sn($sk)) {
                $beans['sn'] = $sk;
            } else if (IDMan::is_bike_imei($sk)) {
                $beans['imei'] = $sk;
            } else {
                return [];
            }
        }

        if (isset($condition['time_interval_type']) && in_array($condition['time_interval_type'], [1, 2])) {
            if ($condition['time_interval_type'] == 1) {
                if (isset($condition['start_time'])) {
                    $beans['create_time'] = ['>=',$condition['start_time']];
                }
                if (isset($condition['end_time'])) {
                    $beans['create_time'] = ['<=',$condition['end_time']];
                }
            } else if ($condition['time_interval_type'] == 2) {
                if (isset($condition['start_time'])) {
                    $beans['launch_time'] = ['>=',$condition['start_time']];
                }
                if (isset($condition['end_time'])) {
                    $beans['launch_time'] = ['<=',$condition['end_time']];
                }
            }
        }


        if (isset($condition['park_id'])) {
            $beans['park_id'] = $condition['park_id'];
        }

        if (isset($condition['is_bluetooth_set'])) {
            if ($condition['is_bluetooth_set']) {
                $beans['bluetooth_name'] = ['=','not null'];
                $beans['bluetooth_token'] = ['=','not null'];
            } else {
                $beans['ecu_brand'] = 'XIAOAN';
                $beans['bluetooth_name|bluetooth_token'] = 'null';
            }
        }
        $rows = Db::table('tb_bike')->where($beans)->field($sfs)->limit($pos,$limit)->select();
        if ($rows->isEmpty()) {
            return [];
        }
        $l = [];
        foreach ($rows as $row) {
            $l[] = common::sql_row($this->selectlist, $row);
        }
        return $l;
    }

    function update_address($city_id, $bike_id, $address)
    {
        $data = [
            'address' => $address,
            'address_update_time' => date('Y-m-d H:i:s'),
        ];

        $where = [
            'city_id' => $city_id,
            'id' => $bike_id,
        ];
        Db::table('tb_bike')->where($where)->update($data);
        $this->merge_info($data);

        $this->sync_to_mongo($data, $where);
    }

    function oper_repark_start($city_id, $bike_id, $order_info)
    {
        $data = [
            'bus_state' => BIKE_BUS_STAT_OPER_REPARK,
            'bus_update_time' => date('Y-m-d H:i:s'),
            'last_repark_order_type' => ORDER_TYPE_BIKE_REPARK,
            'last_repark_order_id' => $order_info['id'],
            'last_repark_order_oper_id' => $order_info['user_id'],
            'last_repark_order_oper_name' => $order_info['user_name'],
            'last_repark_order_oper_phone' => $order_info['user_phone'],
            'last_repark_order_start_time' => $order_info['create_time'],
            'npa_id' => null,
            'npa_name' => null,
            'park_id' => null,
            'park_name' => null,
        ];
        $where = [
            'city_id' => $city_id,
            'id' => $bike_id,
        ];
        Db::table('tb_bike')->where($where)->update($data);

        $this->merge_info($data);


        $this->sync_to_mongo($data, $where);
    }

    function oper_repark_finish($city_id, $bike_id, $park_info)
    {
        $bike_info = $this->get_info_by_id($bike_id);
        $data = [
            'bus_state' => BIKE_BUS_STAT_IDLE,
            'bus_update_time' => date('Y-m-d H:i:s'),
            'last_repark_order_end_time' => date('Y-m-d H:i:s'),
            'park_coordinate' => $bike_info['coordinate'],
        ];


        $data = array_merge($data, $park_info);

        $where = [
            'city_id' => $city_id,
            'id' => $bike_id,
        ];

        Db::table('tb_bike')->where($where)->update($data);

        $this->merge_info($data);


        $this->sync_to_mongo($data, $where);
    }


    function user_repark_start($city_id, $bike_id, $order_info)
    {
        $data = [
            'bus_state' => BIKE_BUS_STAT_USER_REPARK,
            'bus_update_time' => date('Y-m-d H:i:s'),
            'last_repark_order_type' => ORDER_TYPE_USER_REPARK,
            'last_repark_order_id' => $order_info['id'],
            'last_repark_order_oper_id' => $order_info['user_id'],
            'last_repark_order_oper_name' => $order_info['user_name'],
            'last_repark_order_oper_phone' => $order_info['user_phone'],
            'last_repark_order_start_time' => $order_info['create_time'],
            'npa_id' => null,
            'npa_name' => null,
            'park_id' => null,
            'park_name' => null,
        ];
        $where = [
            'city_id' => $city_id,
            'id' => $bike_id,
        ];
        Db::table('tb_bike')->where($where)->update($data);

        $this->merge_info($data);


        $this->sync_to_mongo($data, $where);
    }

    function user_repark_finish($city_id, $bike_id, $park_info)
    {
        $bike_info = $this->get_info_by_id($bike_id);
        $data = [
            'bus_state' => BIKE_BUS_STAT_IDLE,
            'bus_update_time' => date('Y-m-d H:i:s'),
            'last_repark_order_end_time' => date('Y-m-d H:i:s'),
            'park_coordinate' => $bike_info['coordinate'],
        ];


        $data = array_merge($data, $park_info);

        $where = [
            'city_id' => $city_id,
            'id' => $bike_id,
        ];

        Db::table('tb_bike')->where($where)->update($data);

        $this->merge_info($data);


        $this->sync_to_mongo($data, $where);
    }


    function user_order_start($city_id, $bike_id, $order_info)
    {
        $data = [
            'last_order_id' => $order_info['id'],
            'last_order_oper_id' => $order_info['user_id'],
            'last_order_oper_name' => $order_info['user_name'],
            'last_order_oper_phone' => $order_info['user_phone'],
            'last_order_start_time' => $order_info['create_time'],
            'last_order_end_time' => null,
            'bus_state' => BIKE_BUS_STAT_RIDING,
            'bus_update_time' => date('Y-m-d H:i:s'),
            'npa_id' => null,
            'npa_name' => null,
            'park_id' => null,
            'park_name' => null,
        ];

        $where = [
            'city_id' => $city_id,
            'id' => $bike_id,
        ];
        Db::table('tb_bike')->where($where)->update($data);

        $this->merge_info($data);


        $this->sync_to_mongo($data, $where);
    }

    function battery_change_start($city_id, $bike_id, $order_info)
    {
        $data = [
            'last_battery_change_order_id' => $order_info['id'],
            'last_battery_change_order_oper_id' => $order_info['user_id'],
            'last_battery_change_order_oper_name' => $order_info['user_name'],
            'last_battery_change_order_oper_phone' => $order_info['user_phone'],
            'last_battery_change_order_start_time' => $order_info['create_time'],
            'bus_state' => BIKE_BUS_STAT_BATTERY_CHANGE,
            //'bus_update_time' => date('Y-m-d H:i:s'),
        ];

        $where = [
            'city_id' => $city_id,
            'id' => $bike_id,
        ];

        Db::table('tb_bike')->where($where)->update($data);

        $this->merge_info($data);


        $this->sync_to_mongo($data, $where);
    }

    function user_order_reride($city_id, $bike_info, $order_info)
    {
        $data = [
            'bus_state' => BIKE_BUS_STAT_RIDING,
            'bus_update_time' => date('Y-m-d H:i:s'),
        ];

        $where = [
            'city_id' => $city_id,
            'id' => $bike_info['id'],
        ];
        Db::table('tb_bike')->where($where)->update($data);
        $this->merge_info($data);


        $this->sync_to_mongo($data, $where);
    }

    function set_bus_state_idle($city_id, $bike_id)
    {
        $data = [
            'bus_state' => BIKE_BUS_STAT_IDLE,
            'bus_update_time' => date('Y-m-d H:i:s'),
        ];

        $where = [
            'id' => $bike_id,
            'city_id' => $city_id,
        ];

        Db::table('tb_bike')->where($where)->update($data);

        $this->sync_to_mongo($data, $where);
    }

    function battery_change_finish($city_id, $bike_id)
    {
        $data = [
            'bus_state' => BIKE_BUS_STAT_IDLE,
            'battery_change_count' => Db::raw('battery_change_count+1'),
            'distance' => 0
        ];

        $where = [
            'id' => $bike_id,
            'city_id' => $city_id,
        ];

        Db::table('tb_bike')->where($where)->update($data);

        $this->sync_to_mongo($data, $where);
    }

    function user_order_temp_park($city_id, $bike_info, $order_info)
    {
        $data = [
            'bus_state' => BIKE_BUS_STAT_TEMP_PARK,
            'bus_update_time' => date('Y-m-d H:i:s'),
        ];

        $where = [
            'city_id' => $city_id,
            'id' => $bike_info['id'],
        ];
        Db::table('tb_bike')->where($where)->update($data);
        $this->merge_info($data);


        $this->sync_to_mongo($data, $where);
    }

    function user_order_reserve($city_id, $bike_id, $order_info)
    {
        $data = [
            'last_order_id' => $order_info['id'],
            'last_order_oper_id' => $order_info['user_id'],
            'last_order_oper_name' => $order_info['user_name'],
            'last_order_oper_phone' => $order_info['user_phone'],
            'last_order_start_time' => $order_info['create_time'],
            'bus_state' => BIKE_BUS_STAT_RESERVED,
            'bus_update_time' => date('Y-m-d H:i:s'),
        ];

        $where = [
            'city_id' => $city_id,
            'id' => $bike_id,
        ];
        Db::table('tb_bike')->where($where)->update($data);
        $this->merge_info($data);

        $this->sync_to_mongo($data, $where);
    }

    function user_order_finish($city_id, $bike_id, $park_info,$distance,$is_flush =0)
    {
        $bike_info = $this->get_info_by_id($bike_id);

        $flush_count = $bike_info['is_flush_order_count'];

        $data = [
            'last_order_end_time' => date('Y-m-d H:i:s'),
            'bus_state' => BIKE_BUS_STAT_IDLE,
            'bus_update_time' => date('Y-m-d H:i:s'),
            'park_coordinate' => $bike_info['coordinate'],
            'is_flush_order_count' => 0,
        ];
        $park_info = common::type_conver($park_info, $this->selectlist);

        $data = array_merge($data, $park_info);
        if ($park_info['park_state'] == BIKE_PARK_STAT_OSA || $park_info['park_state'] == BIKE_PARK_STAT_NPA) {
            $data['repark_index'] = 1;
        }

        if ($is_flush == 1){
            $flush_count = $flush_count + 1;
            $data['is_flush_order_count'] = $flush_count;
        }

        if($distance > 0){
            $data['distance'] = $bike_info['distance'] + $distance;
        }

        $where = [
            'city_id' => $city_id,
            'id' => $bike_id,
        ];
        Db::table('tb_bike')->where($where)->update($data);
        $this->merge_info($data);

        $this->sync_to_mongo($data, $where);


        if ($is_flush == 1 && $flush_count == 5){
            //al通知
            $city_info = (new PlatformModel())->get_city_al_token($city_id);
            if ($city_info) {
                $alert_desc = "【疑似故障】车辆". $bike_info['sn'] ."连续5位用户产生短时订单，疑似故障,请安排核实。";

                if ($bike_info['is_defend_on']) {
                    $alert_desc = $alert_desc . " [设防]";
                } else {
                    $alert_desc = $alert_desc . " [撤防]";
                }
                if ($bike_info['is_acc_on']) {
                    $alert_desc = $alert_desc . " [电门开]，";
                } else {
                    $alert_desc = $alert_desc . " [电门关]";
                }
                if ($bike_info['is_online']) {
                    $alert_desc = $alert_desc . "[在线]";
                } else {
                    $alert_desc = $alert_desc . "[离线更新时间{$bike_info['online_update_time']}]";
                }

                $alert_desc = $alert_desc . ' [电压:' . $bike_info['battery_volt'] . " {$bike_info['battery_level']}%]";

                $ding = new AliDingDing($city_info['al_token']);
                $ding->assign('text', $alert_desc)
                    ->at(true)
                    ->send();
            }
        }
    }

    function set_alert($city_id, $bike_id, $alert_type)
    {
        $bike_info = $this->get_info_by_id($bike_id);
        if ($bike_info['alert_state'] & $alert_type)
            return;

        $new_alert_state = $bike_info['alert_state'] | $alert_type;

        $info = [
            'alert_state' => $new_alert_state,
        ];

        if ($bike_info['alert_state'] == 0) {
            $info['alert_update_time'] = date('Y-m-d H:i:s');
        }

        $where = [
            'id' => $bike_id,
            'city_id' => $city_id,
        ];

        Db::table('tb_bike')->where($where)->update($info);
        $this->merge_info($info);

        $this->sync_to_mongo($info, $where);
    }

    function unset_alert($city_id, $bike_id, $alert_type)
    {
        $bike_info = $this->get_info_by_id($bike_id);
        if (($bike_info['alert_state'] & $alert_type) == 0)
            return;
        $new_alert_state = ($bike_info['alert_state'] & ~$alert_type);
        $info = [
            'alert_state' => $new_alert_state,
        ];

        if ($new_alert_state == 0) {
            $info['alert_update_time'] = date('Y-m-d H:i:s');
        }


        $where = [
            'id' => $bike_id,
            'city_id' => $city_id,
        ];

        Db::table('tb_bike')->where($where)->update($info);
        $this->merge_info($info);

        $this->sync_to_mongo($info, $where);
    }

    function set_health_state($city_id, $bike_id, $health_state, $health_desc)
    {
        $data = [
            'health_state' => $health_state,
            'health_desc' => $health_desc,
            'health_update_time' => date('Y-m-d H:i:s'),
        ];

        if ($health_state == 0) {
            $data['inv_state'] = 0;
        }

        $where = [
            'city_id' => $city_id,
            'id' => $bike_id,
        ];
        Db::table('tb_bike')->where($where)->update($data);
        $this->merge_info($data);


        $this->sync_to_mongo($data, $where);
    }

    function bus_inv_recall($city_id, $bike_id, $warehouse_id, $warehouse_name)
    {
        $data = [
            'inv_state' => BIKE_INV_STATE_RECALL,
            'warehouse_id' => $warehouse_id,
            'warehouse_name' => $warehouse_name,
            'inv_update_time' => date('Y-m-d H:i:s'),
        ];

        $where = [
            'city_id' => $city_id,
            'id' => $bike_id,
        ];
        Db::table('tb_bike')->where($where)->update($data);
        $this->merge_info($data);

        $this->sync_to_mongo($data, $where);
    }

    function get_ecu_info_by_sn($sn)
    {
        $selectlist = [
            'sn' => 'string',
            'imei' => 'string',
            'brand' => 'string',
            'model' => 'string',
            'bluetooth_token' => 'string',
        ];

        $sfs = common::array_keys($selectlist);


        $beans = [
            'sn'=>$sn,
        ];

        $rows = Db::table('tb_ecu')->where($beans)->field($sfs)->find();

        if (!empty($rows)) {
            return common::sql_row($selectlist, $rows);
        }
        return null;
    }

    function get_ecu_info_by_imei($imei)
    {
        $selectlist = [
            'sn' => 'string',
            'imei' => 'string',
            'brand' => 'string',
            'model' => 'string',
        ];

        $sfs = common::array_keys($selectlist);


        $beans = [
            'imei'=>$imei,
        ];

        $rows = Db::table('tb_ecu')->where($beans)->field($sfs)->find();

        if (!empty($rows)) {
            return common::sql_row($selectlist, $rows);
        }
        return null;
    }

    function add($bike_info)
    {
        $paramlist = [
            'sn' => 'string',
            'city_id' => 'string',
            'model' => 'string',
            'warehouse_id' => 'string',
            'warehouse_name' => 'string',
            'bike_brand' => 'string',
            'bike_model' => 'string',
            'imei' => 'string',
            'ecu_sn' => 'string',
            'ecu_brand' => 'string',
            'ecu_model' => 'string',
            'battery_model' => 'string',
            'product_batch_number' => 'string',
            'brand' => 'string',
            'battery_capacity' => 'int',
            'bluetooth_token' => 'string',
        ];
        $bike_info = common::type_conver($bike_info, $paramlist);
        $info = [
            'id' => IDMan::bike_id($bike_info['city_id'], $bike_info['sn']),
            'health_state' => 0,
            'inv_state' => BIKE_INV_STATE_INFO_INIT,
            'bus_state' => 0,
            'sim_state' => 0,
            'alert_state' => 0,
            'is_deleted' => 0,
            'repark_index' => 0,
            'is_under_volt' => 0,
            'battery_change_count' => 0,
            'is_on_battery' => 1,
            'is_low_battery' => 0,
            'gms_signal_strength' => 0,
            'is_defend_on' => 1,
            'maintain_count' => 0,
            'low_battery_scaned_count' => 0,
        ];

        $datenow = date('Y-m-d H:i:s');

        $default = [
            'health_state' => 0,
            'bus_state' => 0,
            'sim_state' => 0,
            'alert_state' => 0,
            'speed' => 0,
            'is_in_motion' => 0,
            'is_online' => 'int',
            'is_battery_locked' => 1,
            'is_acc_on' => 0,
            'is_wheel_locked' => 1,
            'battery_volt' => 50000,
            'battery_level' => 100,
            'battery_range' => 40,
            'battery_update_time' => $datenow,
            'is_under_volt' => 0,
            'coordinate' => [0, 0],
            'gps_update_time' => $datenow,
            'bus_update_time' => $datenow,
            'health_update_time' => $datenow,
            'is_deleted' => 0,
            'battery_change_count' => 0,
            'inv_update_time' => $datenow,
            'is_on_battery' => 1,
            'is_low_battery' => 0,
            'course' => 0,
            'hdop' => 0,
            'satellite' => 0,
            'is_defend_on' => 1,
            'is_sleeping' => 0,
            'online_update_time' => $datenow,
            'gsm_signal_strength' => 0,
            'sw' => 0,
            'address_update_time' => $datenow,
            'last_maintain_time' => $datenow,
            'maintain_count' => 0,
            'defend_update_time' => $datenow,
            'motion_update_time' => $datenow,
            'battery_lock_update_time' => $datenow,
            'repark_index' => 0,
            'last_scaned_time' => $datenow,
            'last_scaned_user_coordinate' => [0, 0],
            'park_coordinate' => [0, 0],
        ];

        $bike_info = array_merge($default, $bike_info);

        ApiOper::instance()->append_creater_info($bike_info);
        $bike_info = array_merge($bike_info, $info);
        Db::table('tb_bike')->insert($bike_info);

        $this->save_to_mongo($bike_info);

        return $bike_info;
    }

    function launch_to_market($city_id, $bike_id)
    {
        $bike_info = $this->get_info_by_id($bike_id);
        $new_id = $city_id . $bike_info['sn'];
        $data = [
            'id' => $new_id,
            'inv_state' => BIKE_INV_STATE_IN_MARKET,
            'inv_update_time' => date('Y-m-d H:i:s'),
            'launch_time' => date('Y-m-d H:i:s'),
            'bus_update_time' => date('Y-m-d H:i:s'),
            'bus_state' => 0,
            'last_order_id' => null,
            'last_order_oper_id' => null,
            'last_order_oper_name' => null,
            'last_order_oper_phone' => null,
            'last_order_start_time' => null,
            'last_order_end_time' => null,
            'last_repark_order_type' => null,
            'last_repark_order_id' => null,
            'last_repark_order_oper_id' => null,
            'last_repark_order_oper_name' => null,
            'last_repark_order_oper_phone' => null,
            'last_repark_order_start_time' => null,
        ];
        if ($bike_info['city_id'] != $city_id) {
            $data['city_id'] = $city_id;
        }

        $where = [
            'id' => $bike_id,
        ];

        hisql::update('tb_bike', $data, $where);
        $this->merge_info($data);

        $this->sync_to_mongo($data, $where);
        return $this->_info;
    }

    function on_event_ping($city_id, $id, $data)
    {
        $where = [
            'city_id' => $city_id,
            'id' => $id,
        ];
        Db::table('tb_bike')->where($where)->update($data);
        $this->merge_info($data);

        $this->sync_to_mongo($data, $where);
    }

    function on_bike_info_update($city_id, $id, $info)
    {
        $vtimer = new vtimer();
        $where = [
            //'city_id' => $city_id,
            'id' => $id,
        ];

        $bike_info = $this->get_info_by_id($id);
        $data = [];
        foreach ($info as $k => $v) {
            if (!isset($this->selectlist[$k]))
                continue;

            if (isset($bike_info[$k]) && $bike_info[$k] === $v)
                continue;

            $data[$k] = $v;
        }
        if (empty($data))
            return;

        Db::table('tb_bike')->where($where)->update($data);

        $cost = $vtimer->cost();
        Log::debug('on bike info update mysql', $city_id, $id, $info, "cost={$cost}");

        $this->merge_info($data);

        $this->sync_to_mongo($data, $where);

        $cost = $vtimer->cost();
        Log::debug('on bike info update mongo', $city_id, $id, $info, "cost={$cost}");
    }

    function on_event_notify($imei, $event_type)
    {

    }

    function maintain($bike_id)
    {
        $userinfo = ApiOper::instance()->userinfo();
        $bike_info = $this->get_info_by_id($bike_id);

        $info = [
            'last_maintain_time' => date('Y-m-d H:i:s'),
            'last_maintain_user_name' => $userinfo['name'],
            'last_maintain_user_id' => $userinfo['id'],
            'maintain_count' => $bike_info['maintain_count'] + 1,
            'bus_update_time' => date('Y-m-d H:i:s'),
        ];

        $where = [
            'id' => $bike_id,
        ];
        Db::table('tb_bike')->where($where)->update($info);
        $this->merge_info($info);


        $this->sync_to_mongo($info, $where);
    }

    function user_scaned($id)
    {
        $userinfo = ApiOper::instance()->userinfo();
        $info = [
            'last_scaned_time' => date('Y-m-d H:i:s'),
            'last_scaned_user_id' => $userinfo['id'],
            'last_scaned_user_name' => $userinfo['name'],
            'last_scaned_user_coordinate' => isset($userinfo['user_coordinate']) ? $userinfo['user_coordinate'] : null,
        ];

        $where = [
            'id' => $id,
        ];
        Db::table('tb_bike')->where($where)->update($info);
        $this->sync_to_mongo($info, $where);
    }

    function incr_low_battery_scaned_count($id)
    {
        $beans = [
            'id'=>$id
        ];
        Db::table('tb_bike')->where($beans)->setInc('low_battery_scaned_count',1);
    }

    function reset_low_battery_scaned_count($id)
    {
        $data = [
            'low_battery_scaned_count' => 0,
        ];
        $where = [
            'id' => $id,
        ];

        Db::table('tb_bike')->where($where)->update($data);
    }

    function unbind_ecu($id)
    {
        $bike_info = $this->get_info_by_id($id);

        $data = [
            'ecu_sn' => null,
            'imei' => null,
        ];
        $where = [
            'id' => $id,
        ];
        Db::table('tb_bike')->where($where)->update($data);

        $bound_order_info = [
            'order_type' => null,
            'order_id' => $bike_info['imei'],
            'op' => 'ECU解绑',
        ];

        (new BikeOperRecordModel())->add(BIKE_OPER_TYPE_ECU_UNBIND, $bike_info['city_id'], $id, $bound_order_info, null);
    }

    function bind_ecu($id, $imei, $ecu_sn)
    {
        $data = [
            'imei' => $imei,
            'ecu_sn' => $ecu_sn,
        ];

        $where = [
            'id' => $id,
        ];
        Db::table('tb_bike')->where($where)->update($data);

        $bike_info = $this->get_info_by_id($id);

        $bound_order_info = [
            'order_type' => null,
            'order_id' => $imei,
            'op' => 'ECU绑定',
        ];

        (new BikeOperRecordModel())->add(BIKE_OPER_TYPE_ECU_BIND, $bike_info['city_id'], $id, $bound_order_info, null);
    }


    function change_sn($id, $sn)
    {
        $data = [
            'sn' => $sn,
        ];
        $where = [
            'id' => $id,
        ];

        Db::table('tb_bike')->where($where)->update($data);
        $this->sync_to_mongo($data, $where);

        $bike_info = $this->get_info_by_id($id);

        $bound_order_info = [
            'order_type' => null,
            'order_id' => $sn,
            'op' => '更换SN:' . $sn,
        ];

        (new BikeOperRecordModel())->add(BIKE_OPER_TYPE_CHANGE_SN, $bike_info['city_id'], $id, $bound_order_info, null);
    }

    function query_list_maintain($cd)
    {
        $city_id = $cd['city_id'];
        $is_maintained = (isset($cd['is_maintained']) && $cd['is_maintained']);
        $pos = $cd['pos'];
        $limit = $cd['limit'];

        $selectlist = [
            'id' => 'string',
            'sn' => 'string',
            'last_maintain_time' => 'string',
            'last_maintain_user_id' => 'string',
            'last_maintain_user_name' => 'string',
            'maintain_count' => 'int',
            'launch_time' => 'string',
        ];
        $selectlist = array_merge($selectlist, $this->summary_selectlist);
        $sfs = common::array_keys($selectlist);
        $datetime = date('Y-m-d H:i:s', strtotime("-1 month"));

        $st = null;
        $beans = [
            'city_id' => $city_id,
            'is_deleted' => 0
        ];
        $query = new Query();
        if ($is_maintained) {
            $query->where('last_maintain_time','>',$datetime);
            $st = "select SQL_CALC_FOUND_ROWS $sfs  from tb_bike where  city_id = ? and last_maintain_time > ?";
        } else {
           $query->where('last_maintain_time', ['=', null], ['<', $datetime], 'or');
        }

        if (isset($cd['sk']) && !empty($cd['sk'])) {
            $sk = $cd['sk'];
            if (common::is_name($sk)) {
                $beans['last_maintain_user_name'] = $sk;
            } else if (IDMan::is_bike_id($sk)) {
                $beans['id'] = $sk;
            }
        }

        $rows = Db::table('tb_bike')->where($beans)->where($query)->field($sfs)->limit($pos,$limit)->select();
        if ($rows->isEmpty()) {
            return [];
        }
        $l = [];
        foreach ($rows as $row) {
            $l[] = common::sql_row($selectlist, $row);
        }
        return $l;
    }

    function query_list_miss($cd)
    {
        $city_id = $cd['city_id'];
        $selectlist = [
            'id' => 'string',
            'sn' => 'string',
            'bus_state' => 'int',
            'inv_state' => 'int',
            'alert_state' => 'int',
            'health_state' => 'int',
            'battery_level' => 'int',
            'coordinate' => 'array',
            'is_online' => 'int',
            'park_state' => 'int',
        ];

        $sfs = common::array_keys($selectlist);

        $st = null;

        $selectlist = array_merge($selectlist, $this->summary_selectlist);

        $beans = [
            'city_id'=>$city_id,
            'is_deleted' => 0,
            'alert_state' => ['>=',BIKE_ALERT_LONG_NO_GPS],
        ];

        if (isset($cd['sk']) && !empty($cd['sk'])) {
            $sk = $cd['sk'];
            if (IDMan::is_bike_sn($sk)) {
                $beans['sn'] = $sk;
            } else if (IDMan::is_bike_id($sk)) {
                $beans['id'] = $sk;
            }
        }

        if (isset($cd['duration_interval']) && count($cd['duration_interval']) == 2) {
            $s = date('Y-m-d H:i:s', time() - $cd['duration_interval'][1] * 3600);
            $e = date('Y-m-d H:i:s', time() - $cd['duration_interval'][0] * 3600);
            $beans['alert_update_time'] = [['>=',$s],['<=',$e],'and'];
        }

        if (isset($cd['battery_level_interval']) && count($cd['battery_level_interval']) == 2) {
            $beans['battery_level'] = [['>=',$cd['battery_level_interval'][0]],['<=',$cd['battery_level_interval'][1]],'and'];
        }

        $query = new Query();
        if (isset($cd['alert_state'])) {
            $query->where('alert_state | :alert_state > 0',['alert_state'=>$cd['alert_state']]);
        }

        $rows = Db::table('tb_bike')->where($beans)->where($query)->field($sfs)->limit($cd['pos'],$cd['limit'])->select();
        $l = [];
        if (!$rows->isEmpty()) {
            foreach ($rows as $row) {
                $l[] = common::sql_row($selectlist, $row);
            }
        }
        return $l;
    }

    function query_list_stolen($cd)
    {
        $city_id = $cd['city_id'];
        $selectlist = [
            'id' => 'string',
            'sn' => 'string',
            'bus_state' => 'int',
            'inv_state' => 'int',
            'alert_state' => 'int',
            'health_state' => 'int',
            'battery_level' => 'int',
            'coordinate' => 'array',
            'is_online' => 'int',
            'park_state' => 'int',
        ];

        $selectlist = array_merge($selectlist, $this->summary_selectlist);

        $sfs =  common::array_keys($selectlist);

        $st = null;

        $st = "select SQL_CALC_FOUND_ROWS $sfs  from tb_bike where  city_id = ? and alert_state >= ?";


        $beans = [
            'city_id'=>$city_id,
            'is_deleted' => 0,
            'alert_state' => ['>=',BIKE_ALERT_STOLEN],
        ];


        if (isset($cd['sk']) && !empty($cd['sk'])) {
            $sk = $cd['sk'];
            if (IDMan::is_bike_sn($sk)) {
                $beans['sn'] = $sk;
            } else if (IDMan::is_bike_id($sk)) {
                $beans['id'] = $sk;
            }
        }

        if (isset($cd['duration_interval']) && count($cd['duration_interval']) == 2) {
            $s = date('Y-m-d H:i:s', time() - $cd['duration_interval'][1] * 3600);
            $e = date('Y-m-d H:i:s', time() - $cd['duration_interval'][0] * 3600);
            $beans['alert_update_time'] = [['>=',$s],['<=',$e],'and'];
        }

        if (isset($cd['battery_level_interval']) && count($cd['battery_level_interval']) == 2) {
            $beans['battery_level'] = [['>=',$cd['battery_level_interval'][0]],['<=',$cd['battery_level_interval'][1]],'and'];
        }

        $query = new Query();
        if (isset($cd['alert_state'])) {
            $query->where('alert_state & :alert_state > 0',['alert_state'=>$cd['alert_state']]);
        }

        $rows = Db::table('tb_bike')->where($beans)->where($query)->field($sfs)->limit($cd['pos'],$cd['limit'])->select();
        $l = [];
        if (!$rows->isEmpty()) {
            foreach ($rows as $row) {
                $l[] = common::sql_row($selectlist, $row);
            }
        }
        return $l;
    }

    function query_list_alert_fault($cd)
    {
        $city_id = $cd['city_id'];
        $selectlist = [
            'id' => 'string',
            'sn' => 'string',
            'bus_state' => 'int',
            'inv_state' => 'int',
            'alert_state' => 'int',
            'health_state' => 'int',
            'battery_level' => 'int',
            'coordinate' => 'array',
            'is_online' => 'int',
            'park_state' => 'int',
        ];

        $selectlist = array_merge($selectlist, $this->summary_selectlist);
        $sfs = common::array_keys($selectlist);


        $beans = [
            'city_id'=>$city_id,
        ];

        $query = new Query();
        $query->where('alert_state & :alert_state > 0',['alert_state'=>BIKE_ALERT_FAULT]);


        if (isset($cd['sk']) && !empty($cd['sk'])) {
            $sk = $cd['sk'];
            if (IDMan::is_bike_sn($sk)) {
                $beans['sn'] = $sk;
            } else if (IDMan::is_bike_id($sk)) {
                $beans['id'] = $sk;
            }
        }

        $rows = Db::table('tb_bike')->where($beans)->where($query)->field($sfs)->limit($cd['pos'],$cd['limit'])->select();
        $l = [];
        if (!$rows->isEmpty()) {
            foreach ($rows as $row) {
                $l[] = common::sql_row($selectlist, $row);
            }
        }
        return $l;
    }

    function query_list_inv($cd)
    {
        $city_id = $cd['city_id'];
        $pos = $cd['pos'];
        $limit = $cd['limit'];

        $selectlist = [
            'id' => 'string',
            'sn' => 'string',
            'ecu_sn' => 'string',
            'imei' => 'string',
            'model' => 'string',
            'product_batch_number' => 'string',
            'inv_state' => 'int',
            'launch_time' => 'string',
            'create_time' => 'string',
        ];

        $selectlist = array_merge($selectlist, $this->summary_selectlist);
        $sfs = common::array_keys($selectlist);

        $st = null;
        $beans = [
            'city_id'=>$city_id,
            'is_deleted' => 0
        ];


        if (isset($cd['inv_state'])) {
            $beans['inv_state'] = $cd['inv_state'];
        }

        if (isset($cd['start_time'])) {
            $st = $st . " and create_time >= ? ";
            $beans['create_time'] = ['>=',$cd['start_time']];
        }
        if (isset($cd['end_time'])) {
            $st = $st . " and create_time <= ? ";
            $beans['create_time'] = ['<=',$cd['end_time']];
        }
        if (isset($cd['sk']) && !empty($cd['sk'])) {
            $sk = $cd['sk'];
            if (common::is_name($sk)) {
                $beans['last_maintain_user_name'] = $sk;
            } else if (IDMan::is_bike_sn($sk)) {
                $beans['sn'] = $sk;
            } else if (IDMan::is_bike_id($sk)) {
                $beans['id'] = $sk;
            }
        }

        $rows = Db::table('tb_bike')->where($beans)->field($sfs)->limit($pos,$limit)->select();
        $l = [];
        if (!$rows->isEmpty()) {
            foreach ($rows as $row) {
                $l[] = common::sql_row($selectlist, $row);
            }
        }
        return $l;
    }

    function query_list_monitor($cd)
    {
        $city_id = $cd['city_id'];
        $selectlist = [
            'id' => 'string',
            'sn' => 'string',
            'bus_state' => 'int',
            'inv_state' => 'int',
            'alert_state' => 'int',
            'health_state' => 'int',
            'battery_level' => 'int',
            'coordinate' => 'array',
            'is_online' => 'int',
            'park_state' => 'int',
        ];

        $selectlist = array_merge($selectlist, $this->summary_selectlist);
        $sfs = common::array_keys($selectlist);

        $st = null;
        $beans = [
            'city_id'=>$city_id,
            'is_deleted' => 0,
        ];


        if (isset($cd['park_state'])) {
            $beans['park_state'] = $cd['park_state'];
        }
        if (isset($cd['health_state'])) {
            $beans['health_state'] = $cd['health_state'];
        }
        if (isset($cd['battery_level_interval']) && count($cd['battery_level_interval']) == 2) {
            $beans['battery_level'] = [['>=',$cd['battery_level_interval'][0]],['<=',$cd['battery_level_interval'][1]],'and'];
        }

        if (isset($cd['is_defend_on'])) {
            $beans['is_defend_on'] = $cd['is_defend_on'];
        }
        if (isset($cd['model'])) {
            $beans['model'] = $cd['model'];
        }

        $query = new Query();
        if (isset($cd['alert_state'])) {
            $query->where('alert_state > 0 and  alert_state & :alert_state > 0',[':alert_state'=>$cd['alert_state']]);
        }
        if (isset($cd['inv_state'])) {
            $beans['inv_state'] = $cd['inv_state'];
        }
        if (isset($cd['use_state'])) {
            $beans['bus_state'] = $cd['use_state'];
        }

        if (isset($cd['sk']) && !empty($cd['sk'])) {
            $sk = $cd['sk'];
            if (common::is_name($sk)) {
                $beans['last_maintain_user_name'] = $sk;
            } else if (IDMan::is_bike_sn($sk)) {
                $beans['sn'] = $sk;
            } else if (IDMan::is_bike_id($sk)) {
                $beans['id'] = $sk;
            }
        }

        $rows = Db::table('tb_bike')->where($beans)->where($query)->field($sfs)->select();
        $l = [];
        if (!empty($rows)) {
            foreach ($rows as $row) {
                $l[] = common::sql_row($selectlist, $row);
            }
        }
        return $l;
    }

    function query_bike_count($city_id)
    {
        return Db::table('tb_bike')->where(['city_id' => $city_id, 'is_deleted' => 0,'inv_state' =>0])->count('id');
    }

    function query_list_alert($cd)
    {
        $city_id = $cd['city_id'];
        $selectlist = [
            'id' => 'string',
            'sn' => 'string',
            'bus_state' => 'int',
            'inv_state' => 'int',
            'alert_state' => 'int',
            'health_state' => 'int',
            'battery_level' => 'int',
            'coordinate' => 'array',
            'is_online' => 'int',
            'park_state' => 'int',
            'is_dispatched' => 'int',
            'last_dispatch_order_id'=>'string',     //最后派单单号
        ];
        $selectlist = array_merge($selectlist, $this->summary_selectlist);

        $sfs = common::array_keys($selectlist);

        $st = null;
        $beans = [
            'city_id'=>$city_id,
        ];

        $query = new Query();
        if (isset($cd['alert_state'])) {
            $query->where("alert_state > 0 and  alert_state & :k > 0",['k'=>$cd['alert_state']]);
        }

        if (isset($cd['start_time'])) {
            $beans['alert_update_time'] = ['>=',$cd['start_time']];
        }
        if (isset($cd['end_time'])) {
            $beans['alert_update_time'] = ['<=',$cd['end_time']];
        }

        if (isset($cd['sk']) && !empty($cd['sk'])) {
            $sk = $cd['sk'];
            if (IDMan::is_bike_sn($sk)) {
                $beans['sn'] = $sk;
            } else if (IDMan::is_bike_id($sk)) {
                $beans['id'] = $sk;
            }
        }
        if (isset($cd['duration_interval']) && count($cd['duration_interval']) == 2) {
            $s = date('Y-m-d H:i:s', time() - $cd['duration_interval'][1] * 3600);
            $e = date('Y-m-d H:i:s', time() - $cd['duration_interval'][0] * 3600);
            $beans['alert_update_time'] = [['>=',$s],['<=',$e],'and'];
        }
        if (isset($cd['battery_level_interval']) && count($cd['battery_level_interval']) == 2) {
            $s = $cd['battery_level_interval'][0];
            $e = $cd['battery_level_interval'][1];
            $beans['battery_level'] = [['>=',$s],['<=',$e],'and'];
        }

        $query2 = new Query();
        if (isset($cd['reparkflag']) && $cd['reparkflag'] > 1){
            $flag = $cd['reparkflag'];

            $flag_array = [];
            if ($flag & 2) {
                $flag_array[] = 1;
            }

            if ($flag & 4) {
                $flag_array[] = 2;
            }

            if ($flag & 8) {
                $flag_array[] = 3;
            }

            if ($flag & 16) {
                $flag_array[] = 4;
            }

            $num = count($flag_array);
            $tmp_arr =[];
            for($i=0;$i<$num;$i++) {
                if ($i ==0){
                    $st = $st . '(';
                }

                if ($i != $num-1){
                    $st = $st . ' repark_index = ? or';
                }
                else{
                    $st = $st . ' repark_index = ?)';
                }

                $tmp_arr[] = $flag_array[$i];
                $query2->where($st,$tmp_arr);

            }
        }

        $beans['is_deleted'] = 0;

        $rows = Db::table('tb_bike')->where($beans)->where($query)->where($query2)->field($sfs)->limit($cd['pos'],$cd['limit'])->select();
        $l = [];
        if (!$rows->isEmpty()) {
            foreach ($rows as $row) {
                $l[] = common::sql_row($selectlist, $row);
            }
        }
        return $l;
    }

    function query_list_warn($cd)
    {
        $city_id = $cd['city_id'];
        $selectlist = [
            'id' => 'string',
            'sn' => 'string',
            'bus_state' => 'int',
            'inv_state' => 'int',
            'alert_state' => 'int',
            'health_state' => 'int',
            'battery_level' => 'int',
            'coordinate' => 'array',
            'is_online' => 'int',
            'park_state' => 'int',
            'is_dispatched' => 'int',
            'last_dispatch_order_id'=>'string',     //最后派单单号
        ];
        $selectlist = array_merge($selectlist, $this->summary_selectlist);

        $sfs = common::array_keys($selectlist);

        $st = null;
        $beans = [
           'city_id'=> $city_id,
        ];

        if (isset($cd['sk']) && !empty($cd['sk'])) {
            $sk = $cd['sk'];
            if (IDMan::is_bike_sn($sk)) {
                $beans['sn'] = $sk;
            } else if (IDMan::is_bike_id($sk)) {
                $beans['id'] = $sk;
            }
        }
        $query2 = new Query();
        if (isset($cd['reparkflag']) && $cd['reparkflag'] > 1){
            $flag = $cd['reparkflag'];

            $flag_array = [];
            if ($flag & 2) {
                $flag_array[] = 1;
            }

            if ($flag & 4) {
                $flag_array[] = 2;
            }

            if ($flag & 8) {
                $flag_array[] = 3;
            }

            if ($flag & 16) {
                $flag_array[] = 4;
            }

            $num = count($flag_array);
            $tmp_arr=[];
            for($i=0;$i<$num;$i++) {
                if ($i ==0){
                    $st = $st . 'and (';
                }

                if ($i != $num-1){
                    $st = $st . ' repark_index = ? or';
                }
                else{
                    $st = $st . ' repark_index = ?)';
                }

                $tmp_arr[] = $flag_array[$i];
                $query2->where($st,$tmp_arr);
            }
        }
        else {
            $query2->where('repark_index','<>',0);
        }

        $beans['is_deleted'] =0;

        $rows = Db::table('tb_bike')->where($beans)->where($query2)->field($sfs)->limit($cd['pos'],$cd['limit'])->select();
        $l = [];
        if (!$rows->isEmpty()) {
            foreach ($rows as $row) {
                $l[] = common::sql_row($selectlist, $row);
            }
        }
        return $l;
    }

    function query_list_to_check()
    {
        $dt = date('Y-m-d H:i:s', time() - 1000);

        $st = "select  id,imei from tb_bike where  is_deleted = 0 and (online_update_time < ? or gps_update_time < ?) and alert_update_time < ?";
        $beans = [
            'is_deleted' =>0,
            'alert_update_time' => ['<',$dt]
        ];

        $query = new Query();
        $query->where('online_update_time|gps_update_time','<',$dt);

        $rows = Db::table('tb_bike')->where($beans)->where($query)->field(['id,imei'])->select();
        $l = [];
        if (!$rows->isEmpty()) {
            foreach ($rows as $row) {
                $l[] = [
                    'id' => strval($row['id']),
                    'imei' => $row['imei']
                ];
            }
        }
        return $l;
    }

    function query_list_low_battery($city_id, $cd, $pos, $limit)
    {
        $selectlist = [
            'id' => 'string',
            'sn' => 'string',
            'bus_state' => 'int',
            'inv_state' => 'int',
            'alert_state' => 'int',
            'health_state' => 'int',
            'battery_level' => 'int',
            'coordinate' => 'array',
            'is_online' => 'int',
            'park_state' => 'int',
            'battery_update_time' => 'string',
            'last_battery_change_order_start_time' => 'string',
            'low_battery_scaned_count' => 'int',
            'model' => 'string',
        ];

        $sfs = common::array_keys($selectlist);

        $st = null;
        $beans = [
           'city_id' =>$city_id,
            'is_low_battery' => ['>',0]
        ];


        if (isset($cd['low_battery_scaned_count_interval']) && count($cd['low_battery_scaned_count_interval']) == 2) {
            $st = $st . " and low_battery_scaned_count >= ?  and low_battery_scaned_count <= ?";
            $beans['low_battery_scaned_count'] = [['>=',$cd['low_battery_scaned_count_interval'][0]],['<=',$cd['low_battery_scaned_count_interval'][1]],'and'];
        }
        if (isset($cd['model'])) {
            $beans['model'] = $cd['model'];
        }
        if (isset($cd['sk']) && !empty($cd['sk'])) {
            $sk = $cd['sk'];
            if (IDMan::is_bike_sn($sk)) {
                $beans['sn'] = $sk;
            } else if (IDMan::is_bike_id($sk)) {
                $beans['id'] = $sk;
            }
        }

        $beans['is_deleted'] = 0;

        //$st = $st . " and is_deleted = 0 limit {$pos}, {$limit}";

        $rows = Db::table('tb_bike')->where($beans)->field($sfs)->limit($pos,$limit)->select();
        $l = [];
        if (!$rows->isEmpty()) {
            foreach ($rows as $row) {
                $l[] = common::sql_row($selectlist, $row);
            }
        }
        return $l;
    }

    function check_gps_failed_list($city_id, $pos, $limit)
    {
        $selectlist = [
            'id' => 'string',
            'sn' => 'string',
            'bus_state' => 'int',
            'inv_state' => 'int',
            'alert_state' => 'int',
            'health_state' => 'int',
            'battery_level' => 'int',
            'coordinate' => 'array',
            'address' => 'string',
            'is_online' => 'int',
            'park_state' => 'int',
            'is_wheel_locked' => 'int',
            'is_defend_on' => 'int',
            'is_acc_on' => 'int',
            'is_battery_locked' => 'int',
            'is_under_volt' => 'int',
            'gps_update_time' => 'string',
        ];

        $sfs = common::array_keys($selectlist);

        $st = null;


        $beans = [
            'city_id'=>$city_id,
            'is_deleted' => 0
        ];

        $query = new Query();

//检查久未更新gps 信息的车辆
        $d = date('Y-m-d H:i:s', time() - 60 * 12);
        $st = $st . "gps_update_time <= :time and alert_state & 8 = 0";

        $query->where($st,['time'=>$d]);

        //$st = $st . " and is_deleted = 0 limit $pos, $limit";

        $rows = Db::table('tb_bike')->where($beans)->where($query)->field($sfs)->limit($pos,$limit)->select();
        $l = [];
        if (!$rows->isEmpty()) {
            foreach ($rows as $row) {
                $bike_info = common::sql_row($this->selectlist, $row);
                $content = "定位失败, 最近定位时间:" . $bike_info['gps_update_time'];
                (new BikeAlertModel())->add($city_id, $bike_info['id'], BIKE_ALERT_GPS_FAILED, $content);
                $l[] = $bike_info['id'];
            }
        }
        return $l;
    }

    function check_exceptional_unlock_list($city_id, $pos, $limit)
    {
        $selectlist = [
            'id' => 'string',
            'sn' => 'string',
            'bus_state' => 'int',
            'inv_state' => 'int',
            'alert_state' => 'int',
            'health_state' => 'int',
            'battery_level' => 'int',
            'coordinate' => 'array',
            'address' => 'string',
            'is_online' => 'int',
            'park_state' => 'int',
            'is_wheel_locked' => 'int',
            'is_defend_on' => 'int',
            'is_acc_on' => 'int',
            'is_battery_locked' => 'int',
            'is_under_volt' => 'int',
            'gps_update_time' => 'string',
        ];

        $sfs = common::array_keys($selectlist);

        $st = null;
        $beans = [
            'city_id'=>$city_id,
        ];

//异常开锁的车辆
        $query = new Query();

        $st = "(bus_state = 0 or bus_state = :bus_state) and is_defend_on = 0 and alert_state & :alert_state  = 0";
        $st = $st . " limit $pos, $limit";

        $query->where($st,['bus_state'=>BIKE_BUS_STAT_TEMP_PARK,'alert_state'=>BIKE_ALERT_EX_UNLOCK]);

        $rows = Db::table('tb_bike')->where($beans)->where($query)->field($sfs)->limit($pos,$limit)->select();
        $l = [];
        if (!$rows->isEmpty()) {
            foreach ($rows as $row) {
                $bike_info = common::sql_row($this->selectlist, $row);
                $content = "异常开锁";
                (new BikeAlertModel())->add($city_id, $bike_info['id'], BIKE_ALERT_EX_UNLOCK, $content);
                $l[] = $bike_info['id'];
            }
        }
        return $l;
    }

    function query_list_nearby($city_id, $coordinate, $distance, $cd)
    {
        $cd = array_merge($cd, [
            'city_id' => $city_id,
            'eftype' => EB_TYPE_BIKE,
        ]);

        $projection = [
            'id' => 1,
            'sn' => 1,
            'bus_state' => 1,
            'battery_level' => 1,
            'is_online' => 1,
            'is_on_battery' => 1,
            'park_state' => 1,
            'battery_range' => 1,
            'health_state' => 1,
            'inv_state' => 1,
            'coordinate' => 1,
            'alert_state' => 1,
            'repark_index' => 1,
            'model' => 1,
        ];

        $ret = himongo::db()->near($coordinate[0], $coordinate[1], $distance, 1000, $cd, $projection);
        $l = [];
        foreach ($ret as $e) {
            $l[] = common::type_conver($e, $this->mongo_field);
        }
        return $l;
    }

    function analyze($city_id)
    {
        $selectlist = [
            'id' => 'string',
            'bus_state' => 'int',
            'inv_state' => 'int',
            'alert_state' => 'int',
            'health_state' => 'int',
            'battery_level' => 'int',
            'is_online' => 'int',
            'park_state' => 'int',
            'is_under_volt' => 'int',
            'online_update_time' => 'string',
        ];

        $sfs = common::array_keys($selectlist);

        $st = null;
        $beans = [
            'is_deleted' => 0
        ];

        if (!empty($city_id)) {
            $beans['city_id'] = $city_id;
        }


        $rows = Db::table('tb_bike')->where($beans)->field($sfs)->select();
        $l = [];
        if (!$rows->isEmpty()) {
            foreach ($rows as $row) {
                $l[] = common::sql_row($selectlist, $row);
            }
        }
        $ret = [
            'total' => count($l),
            'lock_fail_count' => 0,
            'under_volt_count' => 0,
            '24h_offline_count' => 0,
            'unlock_ex_count' => 0,
            'long_unlock_count' => 0,
            'long_battery_unlock_count' => 0,
            'health_count' => 0,
            'fault_count' => 0,
            'ridden_count' => 0,
            'reserved_count' => 0,
            'ops_count' => 0,
            'idle_count' => 0,
            'battery_60_100_count' => 0,
            'battery_40_60_count' => 0, // 35-60
            'battery_20_40_count' => 0, //20-35
            'battery_10_20_count' => 0, //20-35
            'battery_useable_20_count' => 0,
            'battery_unusable_count' => 0,
            'in_svca_count' => 0,
            'out_svca_count' => 0,
            'launch_count' => 0,
            'init_count' => 0,
            'alert_count' => 0,
            'to_check_count' => 0,
            'alert_fault_count' => 0,
            'offline_count' => 0,
        ];

        foreach ($l as $e) {
            if ($e['is_under_volt']) {
                $ret['under_volt_count']++;
            }
            if ($e['is_online'] == 0 && time() - strtotime($e['online_update_time']) > 24 * 3600) {
                $ret['24h_offline_count']++;
            }

            if ($e['is_online'] == 0) {
                $ret['offline_count']++;
            }

            if ($e['alert_state'] > 0) {
                $ret['alert_count']++;
                if ($e['alert_state'] & BIKE_ALERT_EX_UNLOCK) {
                    $ret['unlock_ex_count']++;
                }
                if ($e['alert_state'] & BIKE_ALERT_LOCK_FAILED) {
                    $ret['lock_fail_count']++;
                }

                if ($e['alert_state'] & BIKE_ALERT_EX_LONG_UNLOCK) {
                    $ret['long_unlock_count']++;
                }
                if ($e['alert_state'] & BIKE_ALERT_LONG_BATTERY_UNLOCKED) {
                    $ret['long_battery_unlock_count']++;
                }
                if ($e['alert_state'] >= BIKE_ALERT_LONG_NO_GPS) {
                    $ret['to_check_count']++;
                }
                if ($e['alert_state'] & BIKE_ALERT_FAULT) {
                    $ret['alert_fault_count']++;
                }
            }

            if ($e['bus_state'] == BIKE_BUS_STAT_IDLE) {
                $ret['idle_count']++;
            } else if ($e['bus_state'] == BIKE_BUS_STAT_RIDING || $e['bus_state'] == BIKE_BUS_STAT_TEMP_PARK) {
                $ret['ridden_count']++;
            } else if ($e['bus_state'] == BIKE_BUS_STAT_RESERVED) {
                $ret['reserved_count']++;
            } else {
                $ret['ops_count']++;
            }
            if ($e['battery_level'] >= 60) {
                $ret['battery_60_100_count']++;
            } else if ($e['battery_level'] >= 35 && $e['battery_level'] < 60) {
                $ret['battery_40_60_count']++;
            } else if ($e['battery_level'] >= 20 && $e['battery_level'] < 35) {
                $ret['battery_20_40_count']++;
            } else if ($e['battery_level'] >= 10 && $e['battery_level'] < 20) {
                $ret['battery_10_20_count']++;
            } else if ($e['battery_level'] >= 0 && $e['battery_level'] < 10) {
                $ret['battery_unusable_count']++;
            }

            if ($e['park_state'] == BIKE_PARK_STAT_OSA) {
                $ret['out_svca_count']++;
            } else {
                $ret['in_svca_count']++;
            }
            if ($e['health_state'] == 0) {
                $ret['health_count']++;
            } else {
                $ret['fault_count']++;
            }
            if ($e['inv_state'] == BIKE_INV_STATE_INFO_INIT) {
                $ret['init_count']++;
            } else {
                $ret['launch_count']++;
            }
        }
        return $ret;
    }

    function check($id)
    {
        return;
        $info = [
            'bus_update_time' => date('Y-m-d H:i:s'),
        ];

        $where = [
            'id' => $id,
        ];

        Db::table('tb_bike')->where($where)->update($info);
        $this->merge_info($info);


        $this->sync_to_mongo($info, $where);
    }

    function delete($id)
    {
        $data = [
            'is_deleted' => 1,
        ];
        $where = [
            'id' => $id
        ];

        Db::table('tb_bike')->where($where)->update($data);

        $this->sync_to_mongo($data, $where);
    }

    function deliver($id)
    {
        $data = [
            'inv_state' => BIKE_INV_STATE_DELIVING,
        ];
        $where = [
            'id' => $id
        ];

        Db::table('tb_bike')->where($where)->update($data);

        $this->sync_to_mongo($data, $where);
    }

    function update_bluetooth_name_token($id, $name, $token)
    {
        $data = [
            'bluetooth_token' => $token,
        ];

        if ($name) {
            $data['bluetooth_name'] = $name;
        }

        $where = [
            'id' => $id
        ];

        Db::table('tb_bike')->where($where)->update($data);
    }

    function query_list($cd)
    {
        $selectlist = [
            'ecu_brand' => 'string',
            'ecu_model' => 'string',
            'imei' => 'string',
            'ecu_sn' => 'string',
        ];
        $selectlist = array_merge($selectlist, $this->summary_selectlist);

        $sfs = common::array_keys($selectlist);

        $st = null;
        $beans = [
            'is_deleted' => 0
        ];


        if (isset($cd['city_id'])) {
            $beans['city_id'] = $cd['city_id'];
        }
        if (isset($cd['ecu_brand'])) {
            $beans['ecu_brand'] = $cd['ecu_brand'];
        }

        $rows = Db::table('tb_bike')->where($beans)->field($sfs)->select();
        $l = [];
        if (!$rows->isEmpty()) {
            foreach ($rows as $row) {
                $l[] = common::sql_row($selectlist, $row);
            }
        }
        return $l;
    }

    //查询数据
    function query_list_change_battery($city_id,$model){
        $selectlist = [
            'id' => 'string',
            'battery_level' => 'int',
            'is_under_volt' => 'int',
        ];

        $sfs = common::array_keys($selectlist);

        $st = null;
        $beans = [
            'is_deleted' => 0,
            'inv_state' => 0,
            'bus_state' => 0
        ];

        if (!empty($city_id)) {
            $beans['city_id'] = $city_id;
        }

        if (!empty($model)) {
            $beans['model'] = $model;
        }

        $rows = Db::table('tb_bike')->where($beans)->field($sfs)->select();
        $l = [];
        if (!$rows->isEmpty()) {
            foreach ($rows as $row) {
                $l[] = common::sql_row($selectlist, $row);
            }
        }
        $ret = [
            'total' => count($l),
            'under_volt_count' => 0,    //欠压
            'battery_35_count' => 0,    //35以下
            'battery_30_count' => 0,    //30以下
            'battery_20_count' => 0,    // 20
            'battery_10_count' => 0,    //20
        ];

        foreach ($l as $e) {
            if ($e['is_under_volt']) {
                $ret['under_volt_count']++;
            }
            if ($e['battery_level'] <35) {
                $ret['battery_35_count']++;

                if($e['battery_level']<30){
                    $ret['battery_30_count']++;
                }

                if($e['battery_level']<20){
                    $ret['battery_20_count']++;
                }

                if($e['battery_level']<10){
                    $ret['battery_10_count']++;
                }
            }
        }
        return $ret;
    }

    //查询挪车数据
    function query_list_repark_count($city_id){
        $selectlist = [
            'id' => 'string',
            'park_state' => 'int',
            'repark_index' => 'int',
        ];

        $sfs = common::array_keys($selectlist);

        $st = null;
        $beans = [
            'is_deleted' => 0,
            'inv_state' => 0,
            'bus_state' => 0
        ];

        if (!empty($city_id)) {
            $beans['city_id'] = $city_id;
        }


        $rows = Db::table('tb_bike')->where($beans)->field($sfs)->select();
        $l = [];
        if (!$rows->isEmpty()) {
            foreach ($rows as $row) {
                $l[] = common::sql_row($selectlist, $row);
            }
        }
        $ret = [
            'total' => count($l),
            'npak_count' => 0,    //禁停区
            'osa_count' => 0,       //服务区外
            'park_1_count' => 0,    //
            'park_2_count' => 0,    //
            'park_3_count' => 0,    //
            'park_4_count' => 0,    //
        ];

        foreach ($l as $e) {
            if ($e['park_state'] == BIKE_PARK_STAT_OSA) {
                $ret['osa_count']++;
            }
            else if ($e['park_state'] == BIKE_PARK_STAT_NPA){
                $ret['npak_count']++;
            }

            if ($e['repark_index'] >=1) {
                $ret['park_1_count']++;

                if($e['repark_index']>=2){
                    $ret['park_2_count']++;
                }

                if($e['repark_index']>=3){
                    $ret['park_3_count']++;
                }

                if($e['repark_index']>=4){
                    $ret['park_4_count']++;
                }
            }
        }
        return $ret;
    }
}

class BikeTrackModel
{

    static function KEY($city_id, $bike_id)
    {
        return "BIKE_TRACK|" . $city_id . "|" . $bike_id;
    }

    function add($city_id, $bike_id, $item)
    {
        $key = self::KEY($city_id, $bike_id);
        hiredis::db()->zAdd($key, time(), json_encode($item));
        $r = rand(1, 50);
        if ($r == 1) {
            $count = hiredis::db()->zCard($key);
            if ($count > 1000) {
                hiredis::db()->zRemRangeByRank($key, 0, $count - 500);
            }
        }
    }

    function query_list($city_id, $bike_id, $start_time, $end_time)
    {
        $e = strtotime($end_time);
        $s = strtotime($start_time);

        if ($e - $s > 3600 * 12) {
            $s = $e - 3600 * 12;
        }
        $vals = hiredis::db()->zRevRangeByScore(self::KEY($city_id, $bike_id), $e, $s, [
            'withscores' => false,
        ]);

        $l = [];
        foreach ($vals as $v) {
            $l[] = json_decode($v, true);
        }

        return $l;
    }

}

class BikeTrackModelNEW
{
    static function KEY($city_id, $bike_id)
    {
        return "BIKE_TRACK|" . $city_id . "|" . $bike_id;
    }

    function add($imei, $info)
    {
        $paramlist = [
            'battery_volt' => 'int',
            'battery_level' => 'int',
            'repark_index' => 'int',
            'coordinate' => 'string',
            'speed' => 'int',
            'is_online' => 'int',
            'course' => 'int',
            'hdop' => 'int',
            'park_state' => 'int',
            'bus_state' => 'int',
            'battery_range' => 'int',
            'is_defend_on' => 'int',
            'is_low_battery' => 'int',
            'is_battery_locked' => 'int',
            'alert_state' => 'int',
            'satellite' => 'int',
            'sw' => 'int',
            'locate_type' => 'string',
        ];

        try {
            $tags = [
                'imei' => $imei,
            ];

            $adds = common::type_conver($info, $paramlist);
            if (!empty($adds)) {
                Hiflux::insert('ebikes', $tags, $adds);
            }

        } catch (Exception $e) {
            $logStr = "接口异常，URI：" . $_SERVER['HTTP_HOST'] . "写INFLUXDB 错误:" . $e->getMessage();
            $ding = new AliDingDing(config('app.system_warning_ding_ding_token'));
            $ding->assign('text', $logStr)
                ->at(true)
                ->send();
        }
    }

    function query_track($imei, $start_time, $end_time, $pos, $limit)
    {
        $selectlist = [
            'coordinate' => 'array',
            'speed' => 'int',
            'course' => 'int',
        ];

        $where = " imei = '{$imei}' and time > '{$start_time}' and time < '{$end_time}'";
        $l = Hiflux::query('ebikes', $selectlist, $where, $pos, $limit);

        $arr = [];
        foreach ($l as $item) {
            $arr[] = [
                $item['coordinate'][0],
                $item['coordinate'][1],
                date('Y-m-d H:i:s', $item['time']),
                $item['speed'],
                $item['course'],
            ];
        }
        // hilog::debug($arr);
        return $arr;
    }

    function query($imei, $fields, $start_time, $end_time, $pos, $limit)
    {
        $paramlist = [
            'battery_volt' => 'int',
            'battery_level' => 'int',
            'repark_index' => 'int',
            'coordinate' => 'array',
            'speed' => 'int',
            'is_online' => 'int',
            'course' => 'int',
            'hdop' => 'int',
            'park_state' => 'int',
            'bus_state' => 'int',
            'battery_range' => 'int',
            'is_defend_on' => 'int',
            'is_low_battery' => 'int',
            'is_battery_locked' => 'int',
            'alert_state' => 'int',
            'satellite' => 'int',
            'sw' => 'int',
            'locate_type' => 'string',
        ];
        $sl = [];
        foreach ($fields as $f) {
            if (isset($paramlist[$f])) {
                $sl[$f] = $paramlist[$f];
            }
        }
        if (empty($sl)) {
            return [];
        }

        $where = " imei = '{$imei}' and time > '{$start_time}' and time < '{$end_time}'";
        $l = Hiflux::query('ebikes', $sl, $where, $pos, $limit);
        return $l;
    }
}


class EcuLogModelNew
{
    static function to_kvs($data, &$kvs, $pk = null)
    {
        if (is_array($data)) {
            foreach ($data as $k => $v) {
                $ktm = $k;
                if (!empty($pk)) {
                    $ktm = $pk . "." . $k;
                }
                if (is_array($v)) {
                    self::to_kvs($v, $kvs, $ktm);
                } else {
                    $kvs[$ktm] = $v;
                }
            }
        }
    }

    function add($sn, $event_type, $raw)
    {
        $measurement = 'eculogs';
        $tags = [
            'sn' => $sn,
            'event_type' => $event_type,
        ];
        $fields = [
            'raw' => $raw,
        ];
        self::to_kvs([], $fields, null);
        Hiflux::insert($measurement,
            $tags,
            $fields
        );
    }


    function query($sn, $start_time, $end_time, $pos, $limit)
    {
        $measurement = 'eculogs';
        $selectlist = [
            'raw' => 'string',
        ];

        $where = " sn = '{$sn}' and time > '{$start_time}' and time < '{$end_time}' order by time desc ";

        $l = Hiflux::query($measurement, $selectlist, $where, $pos, $limit);
        $ltmp = [];
        foreach ($l as $item) {
            $ltmp[] = $item['raw'];
        }
        return $ltmp;
    }

    function count($sn, $start_time, $end_time)
    {
        $measurement = 'eculogs';
        $selectlist = [
            'count(raw)' => 'int',
        ];

        $where = " sn = '{$sn}' and time > '{$start_time}' and time < '{$end_time}'";

        $l = Hiflux::query($measurement, $selectlist, $where, 0, 1);

        if (empty($l)) {
            return 0;
        }

        return $l[0]['count(raw)'];
    }
}
